package net.bat.upload;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.bat.db.BaseDAOImpl;
import net.bat.util.Cfg;
import net.cs.um.UMService;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import dao.hb.UUser;

/**
 * 处理文件上传/管理请求
 * @author chen4w
 * @version 1.0
 */
public class uploadServlet extends HttpServlet {
	public static final String SPLIT_INC = "\t";
	public static final String INDEX_ENCODE = "utf-8";
	public static final String INDEX_FN = "oper.inc";
	//附件最大尺寸2M
	public static final int MAX_LEN = 2048*1024;
	public static final String PATH_SPLITER = "\\";

	private static final String NAME_WORK_PATH="work_path";
	//数据库操作通用对象
	static private BaseDAOImpl dao=null;

	static public BaseDAOImpl getDao() {
		if(dao==null) {
			dao = (BaseDAOImpl)Cfg.getBean("BaseDAOImpl");
		}
		return dao;
	}
	static public void setDao(BaseDAOImpl dao) {
		dao = dao;
	} 	 
	/**
	 * 存放文件的路径
	 */
	static private String path_upload=null;
	static public String getWorkPath(){
		if(File.separatorChar=='/'){
			return Cfg.getInitParameter(NAME_WORK_PATH+"_mac");
		}else{
			return Cfg.getInitParameter(NAME_WORK_PATH+"_win");
		}
	}
	
	static public String getPath(){
		if(path_upload==null){
			path_upload = getWorkPath();
		}
		return path_upload;
	}
	static public void setPath(String path){
		path_upload = path;
	}
  /**
	 * 
	 */
	private static final String REQ_ENCODE="utf-8";
	private static final String ATTACH_ROOT= "/upload";
	private static final long serialVersionUID = 1L;
	/**
	 * http响应类型
	 */
	private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
	static public String splitChar = ",";
	
	//static public int num;
  /**
   * 文件后缀—类型映射表
   */
  static java.util.Hashtable map = new java.util.Hashtable();
  /**
   * 设置所有后缀—类型映射
   */
  static {
      fillMap();
  }
  /**
   * 设置后缀_类型映射
   * @param k 后缀
   * @param v 类型
   */
  static void setSuffix(String k, String v) {
      map.put(k, v);
  }
  /**
   * 设置所有后缀—类型映射
   *
   */
  static void fillMap() {
      setSuffix("", "content/unknown");
      setSuffix(".uu", "application/octet-stream");
      setSuffix(".exe", "application/octet-stream");
      setSuffix(".ps", "application/postscript");
      setSuffix(".zip", "application/zip");
      setSuffix(".sh", "application/x-shar");
      setSuffix(".tar", "application/x-tar");
      setSuffix(".snd", "audio/basic");
      setSuffix(".au", "audio/basic");
      setSuffix(".wav", "audio/x-wav");
      setSuffix(".gif", "image/gif");
      setSuffix(".png", "image/png");
      setSuffix(".jpg", "image/jpeg");
      setSuffix(".jpeg", "image/jpeg");
      setSuffix(".htm", "text/html");
      setSuffix(".html", "text/html");
      setSuffix(".text", "text/plain");
      setSuffix(".c", "text/plain");
      setSuffix(".cc", "text/plain");
      setSuffix(".c++", "text/plain");
      setSuffix(".h", "text/plain");
      setSuffix(".pl", "text/plain");
      setSuffix(".txt", "text/plain");
      setSuffix(".java", "text/plain");
      setSuffix(".svg", "image/svg+xml");
      setSuffix(".doc", "application/msword");
      setSuffix(".docx", "application/msword");
      //setSuffix(".doc", "application/java");
      //setSuffix(".doc", "aapplication/octet-stream");
      setSuffix(".xls", "application/vnd.ms-excel");
      setSuffix(".xlsx", "application/vnd.ms-excel");
      setSuffix(".ppt", "application/mspowerpoint");
      setSuffix(".pptx", "application/mspowerpoint");
      setSuffix(".pdf", "application/pdf");
  }

  private static String bindPath(String fpath,String pathsub){
	  if(pathsub.startsWith(File.separator)){
		  return fpath+pathsub.substring(1);
	  } else {
		return fpath+pathsub;
	}
  }

  public static void makeDir(String fpath,boolean includef){
	  String fb="";
	  String[] fp = fpath.split(":");
	  if(fp.length>1){
		  fb=fp[0]+":";
	  }
	  makeDir(fp[fp.length-1],fb,includef);	    	 	  
  }
  public static void makeDir(String fileDir,String context,boolean includef){
//	 根据目录参数,创建无限层的目录结构
	//如果路径包含文件名,不要将文件名作为目录创建
	if(includef){
		  int pos=fileDir.lastIndexOf(File.separatorChar);
		  fileDir=fileDir.substring(0, pos);
	}
	String fpath = context+fileDir;
	File tf=new File(fpath);
	if(tf.isDirectory() && tf.exists()) {
		return;
	}
	StringTokenizer stringTokenizer = new StringTokenizer(fileDir, "/");
	String strTemp = "";
	while (stringTokenizer.hasMoreTokens()) {
		String str = stringTokenizer.nextToken();
		if("".equals(strTemp)){
			strTemp = str;
		}
		else{
			strTemp = strTemp + "/" + str;
		}
		File dir = new File(context + strTemp);
		if (!dir.isDirectory()) {
			dir.mkdirs();
		}
	}
  } 
  public static String getFileRN(String fnstr){
	  if(fnstr==null) {
		return null;
	}
	  String[] fns = fnstr.split(splitChar);
	  StringBuffer sbuf = new StringBuffer();
	  for(int i=0; i<fns.length; i++){
		  String fn = fns[i];
		  if(i>0) {
			sbuf.append(splitChar);
		}
		  if(fn.startsWith("_")) {
			sbuf.append(fn.substring(1));
		} else {
			sbuf.append(fn);
		}
	  }	  
	  return sbuf.toString();
  }
  public static long getFileSize(String fnstr){
	  if(fnstr==null) {
		return 0;
	}
	  long total =0;
	  String[] fns = fnstr.split(splitChar);
	  for (String fn : fns) {
		  String fpath =  bindPath(getPath(),getFPath(fn));
			File fileIn = new File(fpath);
			if(!fileIn.exists()) {
				continue;
			}
			total += fileIn.length();
	  }
	  return total;
  }
  public static void delFile(String fnstr,String suffix,String spec){
	  if(fnstr==null) {
		return;
	}
	  String[] fns = fnstr.split(splitChar);
	  for (String fn : fns) {
		  String fpath =  bindPath(getPath(),getFPath(fn));
			File fileIn = new File(fpath);
			if(!fileIn.exists()) {
				return;
			}
			fileIn.delete();
	  }
  }

  public static File moveFile(String from,String to) {
	  String path = getPath();
	  String fpo=bindPath(path,getFPath(from));
	  String fnp =getFPath(to);
	  String fpn=bindPath(path,fnp);
	  File fileIn = new File(fpo);
	  if(!fileIn.exists()||fileIn.isDirectory()){
		  return null;
	  }
	  makeDir(fnp,path,true);
	  File fn = new File(fpn);
	  fileIn.renameTo(fn);
	  return fn;
  }
 static public void appendIndex(int uid,char oper,File f) throws IOException{
	 String path_uid = getPath()+File.separator+uid;
	 FileOutputStream fw=new FileOutputStream(path_uid+File.separator+INDEX_FN,true);
	 OutputStreamWriter osw = new OutputStreamWriter(fw,INDEX_ENCODE);
	 osw.write(f.lastModified()+SPLIT_INC
			 +oper+SPLIT_INC
			 +f.getPath().substring(path_uid.length())+SPLIT_INC
			 +f.length()+"\n");
	 osw.flush();
	 osw.close();
	 fw.close();
 }
  public static  String getFPath(String fname){
	  //自定义路径
	  if(fname.indexOf(uploadServlet.PATH_SPLITER)!=-1){
		  return fname.replace(uploadServlet.PATH_SPLITER, File.separator);
	  }
	  String dtstr=fname;
	  int pos1=fname.indexOf("[");
	  int pos2=fname.indexOf("]");
	  if(pos1!=-1 && pos2!=-1) {
		  dtstr=fname.substring(pos1+1, pos2);
		  fname=fname.substring(pos2+1);
	  }
	  String ds[]=dtstr.split("_");
	  String rstr="";
	  for (String element : ds) {
		  rstr+=element+File.separatorChar;
	  }
	  return rstr+fname;
  }
 /**
   * servlet初始化,读入配置文件中的参数
   */
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}

 static public String getURIPath(String uri){
	return bindPath(getPath(),getFPath(uri));
 }
 static public String getBindPath(String fname){
	 return bindPath(getPath(),getFPath(fname));
 }
  static public boolean openfile(HttpServletRequest request, HttpServletResponse response) throws IOException{
	  	String path = getPath();
	  	//request.setCharacterEncoding(REQ_ENCODE);
		String fname = request.getParameter("f");
		//if(fname!=null)
		//	fname = new String(fname.getBytes("ISO-8859-1"),REQ_ENCODE);
		int ipos = fname.indexOf("?");
		if (ipos>0){
			fname = fname.substring(0,ipos);
		}
		String fp = request.getParameter("fp");
		if(fp!=null) {
			fp = new String(fp.getBytes("ISO-8859-1"),REQ_ENCODE);
		} else {
			fp = bindPath(path,getFPath(fname));
		}
		File fileIn = new File(fp);
		if(!fileIn.exists()){
			response.setContentType(CONTENT_TYPE);
			response.setCharacterEncoding(REQ_ENCODE);
			String err_out = "["+fname+"] not found";
			response.sendError(response.SC_NOT_FOUND,err_out);
		  return false;
		}
		try{
	    String ct = null;
	    int ind = fp.lastIndexOf('.');
	    if (ind > 0) {
	     ct = (String) map.get(fp.substring(ind).toLowerCase());
	    }
	    if (ct == null) {
	      ct = "application/octet-stream";
	     }
		  response.setContentType(ct);
		 // response.setHeader("Content-disposition","attachment;filename="+fname);//wjh //加此句打不开jpg

		  //if(ct==null)
			//  response.setHeader("Content-Disposition", "attachment; filename="+FileName);
		  InputStream is = new FileInputStream(fileIn);
		  OutputStream os = response.getOutputStream();//得到输出流
		  byte data[]=new byte[4096];//缓冲字节数
		  int size=is.read(data);
		  while(size!=-1){
		   os.write(data,0,size);
		   size = is.read(data);
		  }
		  is.close();
		  os.flush();
		  os.close();
		  //num++;  //wjh
		  //System.out.println("############num="+num);
		  
		  return true;
		}catch(Exception e){
			return false;
		}
	}
  static public void onSubmit(HttpServletRequest request, HttpServletResponse response) throws Exception{
	  	String path = getPath();
	     request.setCharacterEncoding("UTF-8");
		  //是否指定path
		 String fp = request.getParameter("fp");
		 //是否不需要自动命名
	     //String tid=request.getParameter("tid");
			 
	      boolean writeToFile = true;
	      response.setContentType(CONTENT_TYPE);
	      PrintWriter out = response.getWriter();
	      int total = request.getContentLength();
    	  if(total > MAX_LEN){
    		  throw new IOException("file size must <"+MAX_LEN);
    	  }
	      out.println("OK");
//	    Check that we have a file upload request
	      boolean isMultipart = ServletFileUpload.isMultipartContent(request);
	      if(!isMultipart) {
			return;
		}
	  UploadListener listener = new UploadListener(request,0);
	  // Create a factory for disk-based file items
	  DiskFileItemFactory factory = new MonitoredDiskFileItemFactory(listener);
	  //DiskFileItemFactory  factory = new DiskFileItemFactory();
	  //factory.setSizeThreshold(1024);
	  ServletFileUpload upload = new ServletFileUpload(factory);
      // 解析request
      List items = upload.parseRequest(request);
		UUser usr = UMService.getUserBySession(request);
		int uid = usr.getId();

      // 处理Item
      Iterator iter = items.iterator();
      while (iter.hasNext()) {
          FileItem item = (FileItem) iter.next();
          if (!item.isFormField()){//file
        	   String fpath=item.getName();
        		int pos = fpath.lastIndexOf(File.separatorChar);
        		if(pos!=-1){
        		   fpath=fpath.substring(pos+1);
        		}
               String fileName;
               fileName=  "_["+uid+"]"+listener.getTaskId()+"_"+fpath;
               if (writeToFile) {
                //保存到硬盘设定的目录
            	File uploadedFile;
            	if(fp==null){
	            	String fnp=getFPath(fileName);
	            	makeDir(fnp,path,true);
	                uploadedFile = new File(path +fnp);
            	}else{
            		uploadedFile = new File(fp +fileName);
            	}
                item.write(uploadedFile);
               } else {
                InputStream uploadedStream = item.getInputStream();
                uploadedStream.close();
               }
          }
      }
 }
 	/**
	 * 处理上传文件请求
	 */
  @Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	  try {
		onSubmit(request,response);
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
  }
  @Override
public void destroy() {
  }
  
  @Override
public void doGet( HttpServletRequest request , HttpServletResponse response )  throws ServletException , IOException{
	  openfile(request,response);
  }

}
